new function(currentAnchorClass){
  var
  djp = window['djp'],
  fClose,
  doc = document,
  selectedBlock,
  fReplaceFormReplyWrapper;
  function setProject(oTargetDJProxy, oEvent){
    var
    clickedAnchor = oEvent ? oTargetDJProxy.ancestor().hasNode('A') : oTargetDJProxy,
    currentBlock,
    currentAnchor = djp(clickedAnchor).ancestor()
    .hasClass('r--comments-projects'),
    isNotAll = 3,
    tmp;
    currentAnchorClass = 'r--comments-project-curr';
    clickedAnchor.classIs(currentAnchorClass) && oEvent && oEvent.prevent();
    if(
      !clickedAnchor.classIs(currentAnchorClass) &&
      currentAnchor.node && (
        currentBlock = currentAnchor.next()
        .hasClass('r--comments-login-wrapper')
        .child().hasNode('DIV')
        .child().hasNode('DIV')
        .child().hasNode('FORM')
      ).node
    ){
      clickedAnchor.node.blur();
      currentAnchor = currentAnchor.child().hasNode('A');
      /*parseInt(Number(-1>>>1^1).toString(2),2)*/
      while(currentAnchor.node && currentBlock.node && isNotAll){
        isNotAll = currentAnchor.classIs(currentAnchorClass) ? (
          currentBlock.toggleClass('currentForm', false),
          currentAnchor.toggleClass(currentAnchorClass, false),
          isNotAll & 2
        ) : (
          currentAnchor.node == clickedAnchor.node ? (
            currentBlock.toggleClass('currentForm', true),
            currentAnchor.toggleClass(currentAnchorClass, true),
            (tmp = djp(currentBlock).child().hasAttr('name', 'service_login').node) &&
            tmp.focus(),
            isNotAll & 1
          ) : (
            isNotAll
          )
        )
        currentBlock.more();
        currentAnchor.more();
      }
      oEvent && oEvent.prevent()
    }
  }
  djp(doc).attach('click', setProject);
  window['auth_callback'] = function (json){
    var
    container,
    n = 6;
    // TODO: Stop spinner
    clearTimeout(timer);
    if (!json || json['fail']){
      if(json && json['msg']){
        for(
          container =  djp(selectedBlock)
          .child().more().child()
          .hasClass('r--comments-login-wrapper')
          .child().child().child().hasClass('currentForm').node.lastChild;
          container && (container.nodeType != 1 || container.nodeName != 'DIV');
          container = container.previousSibling
        );
        container.innerHTML = '<span style="color:#B80321">' + json['msg'] + '</span>';
      }
      container = selectedBlock.node;
      (function closureFunc(){
        if (--n) {
          if (n % 2) {
            container['style']['marginLeft'] = '-4px'
          } else {
            container['style']['marginLeft'] = '4px'
          }
          setTimeout(closureFunc, 300 / (n+1))
        } else {
          container['style']['marginLeft'] = '';
        }
      })();
      //alert( "Auth failed. TODO: Stop spinner and return back form (" + (json && json['msg']) + ")" );
    } else {
      djp.send(
        '/comments/auth/form',
        function(text, r){
          var g = /^\s*<[^>]+>\s*<[^>]+class="(?:[^"]*\s+)?r--comments-authorized(?:\s+|")/;
          if(!sFormReplyWrapper || !g.test(sFormReplyWrapper)){
            sFormReplyWrapper = text;
            fReplaceFormReplyWrapper();
            fClose && fClose();
          }else{
            location.reload(true);
          }
        },
        ''
      );
      //alert("Auth success. TODO: Stop spinner and reload top form line and bottom form line");
    }
  };
  var
  targetWin,
  targetWinName = 'CommentsAuth',
  timer;
  function attachSubmitToForm (oTargetDJProxy, oEvent){
    var form = oTargetDJProxy.ancestor().hasNode('FORM');
    if(
      form.ancestor().hasClass('r--comments-login-wrapper').node &&
      form.attr('target') != targetWinName
    ){
      form.attr('target', targetWinName);
      form.attach(
        'submit',
        function (oTargetDJProxy, oEvent){
          // TODO: Start spinner
          targetWin = window.open('javascript:"<html><body>Загрузка</body></html>"', targetWinName, "width=800,height=500");
          (function check4close(){
            timer = setTimeout(
              function (){
                if(targetWin.closed){
                  window['auth_callback']({
                    'msg': 'Ошибка авторизации. Пожалуйста, попробуйте еще раз',
                    'fail': 1
                  });
                } else {
                  check4close()
                }
              },
              300
            );
          })();
        }
      );
    }
  }
  djp(doc).attach(
    'click',
    attachSubmitToForm
  );
  djp(doc).attach(
    'keyup',
    attachSubmitToForm
  );
  showOpenID = function (node, target, commentNode, pos){
    var
    content = doc.createElement('DIV');
    content.innerHTML = sFormReplyWrapper;
    content = djp(content).child().child();
    fClose && fClose();
    fReplaceFormReplyWrapper = function(){
      var
      tmp =  doc.createElement('DIV'),
      oldFormReplyWrapper = node.parentNode,
      oFormReplyWrapper,
      storedAction = djp(node).attr('action'),
      storedMessage = node['message'].value;
      tmp.innerHTML = sFormReplyWrapper;
      oldFormReplyWrapper.parentNode.replaceChild(
        oFormReplyWrapper = tmp.firstChild,
        oldFormReplyWrapper
      );
      tmp = oFormReplyWrapper.getElementsByTagName('FORM');
      djp(tmp = tmp[tmp.length - 1]).attr('action', storedAction);
      attachOnSubmit(
        tmp,
        storedAction,
        commentNode
      );
      tmp['message'].value = storedMessage;
    };
    fClose = djp.openBox.alignLeftInside(
      target,
      {
        openCallback: function(boxNode, recalc, target){
          var anchorNode = boxNode.append(content).toggleClass('nojs', false);
          selectedBlock = djp(anchorNode);
          if(pos){
            anchorNode = anchorNode.child().more().child().more().more().child();
            for(;pos--;){
              anchorNode.more()
            }
            recalc(target, boxNode);
            setProject(anchorNode);
          }
        },
        closeCallback: function(boxNode){
          fClose = null;
        },
        closeClass: 'r--comments-close'
      }
    );
  };
  (function(timer, UNDEFINED){
    djp(doc.documentElement).attach(
      'input keydown keyup cut paste',
      function(oTargetDJProxy, oEvent){
        var
        inputDJP = oTargetDJProxy.ancestor().hasNode('TEXTAREA').hasAttr(
          'maxlength', {
            'test': function(sValue){
              return !!sValue
            }
          }
        );
        if(
          inputDJP.node
        ){
          timer !== UNDEFINED && clearTimeout(timer);
          timer = setTimeout(function(){
            var
            newPos,
            tmp,
            text = inputDJP.node.value,
            beforeText,
            afterText,
            maxCommentLength = parseInt(inputDJP.attr('maxlength'), 10),
            storedScrollLeft = inputDJP.node.scrollLeft,
            storedScrollTop = inputDJP.node.scrollTop,
            overflowLength = text.length -  maxCommentLength,
            lengthNodeDJP = djp(inputDJP.node.form).child().child().hasClass('r-comments-text-counter');
            timer = UNDEFINED;
            if(overflowLength > 0){
              newPos = inputDJP.selectionRange();
              tmp = Math.max(newPos.begin, newPos.end);
              beforeText = text.slice(
                0,
                tmp < overflowLength ? (
                  afterText = text.slice(tmp, tmp - overflowLength),
                  0
                ) : (
                  afterText = text.slice(tmp),
                  tmp - overflowLength
                )
              );
              inputDJP.node.value = text = beforeText + afterText;
              tmp = [
                beforeText.length,
                text.length - afterText.length
              ];
              if(newPos.end == beforeText.length) tmp = tmp.reverse();
              if(newPos.end == newPos.begin) tmp[0] = tmp[1];
              inputDJP.selectionRange({
                begin: tmp[0],
                end: tmp[1]
              });
              inputDJP.node.scrollLeft = storedScrollLeft; 
              inputDJP.node.scrollTop = storedScrollTop
            }
            lengthNodeDJP.text(maxCommentLength - text.length);
          },1)
        }
      }
    )
  })();
  djp(doc).attach(
    'click',
    function(oTargetDJProxy, oEvent){
      var
      pos,
      target = oTargetDJProxy.ancestor().hasClass('auth-form'),
      tmp = djp(target).ancestor().hasClass('r--comments'),
      tmp2;
      if( tmp.node ){
        oEvent.prevent();
        for(
          pos = -1,
          tmp2 = djp(target);
          tmp2.node;
        ){
          pos++;
          tmp2 = tmp2.prev()
        }
        showOpenID(
          djp(tmp).child().hasNode('FORM').node,
          target,
          djp(tmp).ancestor().hasClass('comment-entry').node,
          pos
        );
      }
    }
  );
  
  /* Элемент с классом mOut,
   * при наведении курсора мыши это класс меняется на mOver,
   * и при клике на mDown
   */
  (function(overNode, root, reg){
    function setOut(oDJP){
      if(
        overNode && (
          !oDJP || (
            overNode && oDJP.node != overNode.node
          )
        )
      ){
        overNode
          .toggleClass('mOver mDown', false)
          .toggleClass('mOut', true);
        overNode = 0
      }
      if(oDJP) overNode = djp(oDJP);
    }
    root.attach(
      'mouseover',
      function(oTargetDJProxy, oEvent){
        var oDJP = djp(oTargetDJProxy).ancestor().hasAttr('class', reg);
        if(oDJP.node){
          if(oDJP.classIs('mOut')){
            oDJP
              .toggleClass('mOut', false)
              .toggleClass('mOver', true);
          }
          setOut(oDJP);
        } else {
          setOut()
        }
      }
    );
    root.attach(
      'mousedown',
      function(oTargetDJProxy, oEvent){
        var oDJP = djp(oTargetDJProxy).ancestor().hasAttr('class',reg);
        if(oDJP.node){
          setOut(
            oDJP
              .toggleClass('mOut mOver', false)
              .toggleClass('mDown', true)
          );
        } else {
          setOut()
        }
      }
    );
    root.attach(
      'mouseup',
      function(oTargetDJProxy, oEvent){
        var oDJP = djp(oTargetDJProxy).ancestor().hasAttr('class',/(?:^|\s+)(?:mOver|mDown)(?:\s+|$)/);
        if(oDJP.node){
          oDJP.toggleClass('mDown', false).toggleClass('mOver', true)
        } else {
          setOut()
        }
      }
    );
  })(0, djp(doc), /(?:^|\s+)(?:mOut|mOver|mDown)(?:\s+|$)/);
};